package tech.summerly.weather.data.local

import android.arch.persistence.room.Dao
import android.arch.persistence.room.Insert
import android.arch.persistence.room.Query
import android.support.annotation.VisibleForTesting
import com.google.gson.Gson
import tech.summerly.weather.AppContext
import tech.summerly.weather.model.Region
import tech.summerly.weather.util.Position

@Dao
interface RegionDao {

    @Query("select * from region")
    fun getRegions(): List<Region>

    @Insert
    fun insertRegion(regions: List<Region>)

    @Query("select * from region where fullName like '%'||:query||'%'")
    fun queryRegion(query: String): List<Region>
}


class RegionJsonReader {

    companion object {
        private const val JSON_FILE_NAME = "region.json"
        private const val PROVINCE_SUFFIX = '省'
    }


    /**
     * 读取 assets/region.json 文件，转换其内容到数据库中。
     */
    fun readRegionJson2Db() {
        val allRegion = getAllRegion()
        val instance = RegionDataBase.INSTANCE
        instance.regionDao().insertRegion(allRegion)
    }

    @VisibleForTesting
    fun getChina(): JsonCity {
        val city = Gson().fromJson(AppContext.instance.assets.open(JSON_FILE_NAME).reader(), JsonCity::class.java)
        city.initParentNode()
        return city
    }

    private fun getAllRegion(): List<Region> {
        val china = getChina()
        return china
                .districts
                //首先获取到所有的市级区域
                .flatMap {
                    it.districts
                }.flatMap {
                    val list = ArrayList<JsonCity>(it.districts.size + 1)
                    list.add(it)
                    list.addAll(it.districts)
                    list
                }.map {
                    Region(fullName = it.getFullString(),
                            name = it.name,
                            position = it.center,
                            province = it.getProvince(),
                            city = it.getCity())
                }
    }


    data class JsonCity(
            val name: String,
            val center: Position,
            val level: String,
            val districts: ArrayList<JsonCity>
    ) {
        companion object {
            const val LEVEL_STREET = "street"
            const val LEVEL_DISTRICT = "district"
            const val LEVEL_CITY = "city"
            const val LEVEL_PROVINCE = "province"
            const val LEVEL_COUNTRY = "country"

            const val SEPARATOR = ","

            private fun getLevelInt(level: String) = when (level) {
                LEVEL_STREET, LEVEL_DISTRICT -> 0
                LEVEL_CITY -> 2
                LEVEL_PROVINCE -> 3
                LEVEL_COUNTRY -> 4
                else -> error("错误的level $level")
            }
        }

        //父节点
        var parent: JsonCity? = null

        //初始化所有子节点的父节点
        fun initParentNode() {
            districts.forEach {
                it.parent = this
                it.initParentNode()
            }
        }

        private fun getName(level: String): String {
            var region = this
            var l = getLevelInt(region.level)
            while (l <= getLevelInt(level)) {
                if (l == getLevelInt(level)) {
                    return region.name
                }
                region = region.parent ?: break
                l = getLevelInt(region.level)
            }
            return ""
        }

        fun getProvince(): String {
            return getName(LEVEL_PROVINCE)
        }

        fun getCity(): String {
            return getName(LEVEL_CITY)
        }

        //获取详细地址, 比如 中华人民共和国,澳门特别行政区,花王堂区
        fun getFullString(maxLevel: String = LEVEL_PROVINCE): String {
            val max = getLevelInt(maxLevel)
            val current = getLevelInt(level)
            return when {
                max > current -> {
                    val parent = parent?.getFullString(maxLevel)
                    if (parent.isNullOrEmpty()) {
                        name
                    } else {
                        parent + SEPARATOR + name
                    }
                }
                max == current -> name
                else -> ""
            }
        }


    }

}
